home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------
- #
- # NewsWatcher - Macintosh NNTP Client Application
- #
- # Written by Steven Falkenburg
- # ©1990 Apple Computer, Inc.
- #
- #-----------------------------------------------------------
- #
- # newsprocess.c
- #
- # This code module contains miscellaneous routines
- # called by many of the other code segments.
- # The memory management routines and status window
- # routines are contained in this module.
- #
- #-----------------------------------------------------------*/
-
- #pragma segment newsprocess
-
- #include "compat.h"
-
- #ifdef PROTOS
-
- #include <Types.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <OSUtils.h>
- #include <Desk.h>
- #include <ToolUtils.h>
- #include <OSEvents.h>
- #include <Lists.h>
- #include <CursorCtl.h>
- #include <Packages.h>
- #include <Errors.h>
- #include <CType.h>
- #include <Strings.h>
- #endif
-
- #include <StdIO.h>
- #include <String.h>
-
- #include "nntp.h"
- #include "newsprocess.h"
- #include "userint.h"
- #include "commands.h"
- #include "miscstuff.h"
- #include "netstuff.h"
-
- #ifdef NNTPNEWS
- #include "NNTPLow.h"
- #else
- #include "HFSNTPLow.h"
- #endif
-
-
- /* InitSubjectList is called to set up an empty subject list
- data structure. The subjects are stored in a handle, which
- is dynamically grown and locked.
- */
-
- void InitSubjectList(TwindowInfo *theInfo)
- {
- theInfo->data2 = (unsigned long)MyNewHandle(1);
- HLock((Handle)theInfo->data2);
- theInfo->numSubjects = 0;
- }
-
-
- /* AddToSubjectList gets a range of messages from the NNTP server and puts
- them in the subject list. The data structure is grown accordingly.
- */
-
- void AddToSubjectList(TwindowInfo *theInfo,char *newsGroup,long first,long last)
- {
- ListHandle theList;
- long i,numMessages;
- Cell theCell,oldCell;
- TSubject *theSubjects;
- Str255 tmpStr;
- extern TPrefRec gPrefs;
-
- theList = (ListHandle) theInfo->data;
-
- /* get max specified msgs */
-
- if (last-first > gPrefs.maxFetch)
- first = last-gPrefs.maxFetch;
-
- HUnlock((Handle)theInfo->data2);
- MySetHandleSize((Handle)theInfo->data2,GetHandleSize((Handle)theInfo->data2)+(sizeof(TSubject)*(last-first+1)));
- if (MyMemErr() != noErr) {
- MoveHHi((Handle)theInfo->data2);
- HLock((Handle)theInfo->data2);
- return;
- }
- MoveHHi((Handle)theInfo->data2);
- HLock((Handle)theInfo->data2);
- theSubjects = (TSubject *) *((Handle)theInfo->data2);
-
- LDoDraw(false,theList);
- if (GetMessages(newsGroup,first,last,&theSubjects[theInfo->numSubjects],&numMessages,"SUBJECT") == noErr) {
- StatusWindow("Building Subject List...",-1);
- GiveTime(0);
- for (i=theInfo->numSubjects; i<numMessages+theInfo->numSubjects; i++) {
- SetPt(&theCell,0,0);
- oldCell = theCell;
- strcpy((char *)tmpStr,theSubjects[i].name);
- tmpStr[strlen((char *)tmpStr)+1] = 0xff;
- DisposPtr(theSubjects[i].name);
-
- if (!gPrefs.mostRecentFirst) {
- while (LSearch(tmpStr,strlen((char *)tmpStr)+2,SubjectCompare,&theCell,theList)) {
- theCell.v++;
- oldCell = theCell;
- GiveTime(0);
- }
- if (oldCell.v != 0)
- theCell = oldCell;
- }
- else
- if (!LSearch(tmpStr,strlen((char *)tmpStr)+2,SubjectCompare,&theCell,theList))
- theCell.v = 0;
-
- LAddRow(1,theCell.v,theList);
- LSetCell(tmpStr,strlen((char *)tmpStr)+2,theCell,theList);
- StatusWindow("Building Subject List...",(short)(((float)(i+1)/(float)(numMessages+theInfo->numSubjects))*100));
- GiveTime(0);
- }
- }
- LDoDraw(true,theList);
- theInfo->numSubjects += numMessages;
-
- SetCursor(&QDARROW);
- }
-
-
- /* SubjectCompare is used to determine where to insert a new subject string
- into an existing list of subjects. The Re: and article number are stripped,
- and the subject strings are then compared.
- */
-
- pascal short SubjectCompare(char *aPtr,char *bPtr,short aLen,short bLen)
- {
- /* remove leading space */
-
- aPtr++;
- bPtr++;
- aLen--;
- bLen--;
-
- /* remove article numbers */
-
- while (aPtr && *aPtr != ' ') {
- aPtr++;
- aLen--;
- }
- while (bPtr && *bPtr != ' ') {
- bPtr++;
- bLen--;
- }
-
- /* remove reply indicator */
-
- if (strncmp(aPtr," Re:",4)==0) {
- aPtr += 4;
- aLen -= 4;
- }
- if (strncmp(bPtr," Re:",4)==0) {
- bPtr += 4;
- bLen -= 4;
- }
-
- return IUMagIDString(aPtr,bPtr,aLen,bLen);
- }
-
-
- /* This routine removes colons, check marks, or returns from the titles of
- articles. This insures that the string returned is a legal filename.
- */
-
- char *TitleFilter(char *title)
- {
- short i;
-
- for (i=1; i<=title[0]; i++) {
- switch (title[i]) {
- case CR:
- case ':':
- case '√':
- title[i] = ' ';
- break;
- }
- }
- if (title[0] > 31)
- title[0] = 31;
- return title;
- }
-
-
- /* DoSaveWindow is called when the user issues a Save command for a
- NEW article window. The text of the article is saved to a text file
- on disk.
- */
-
- Boolean DoSaveWindow(WindowPtr wind)
- {
- Point where = {100,100};
- SFReply reply;
- Str255 defaultName;
- TwindowInfo *info;
- OSErr err;
- long count;
- short fRefNum;
-
- GetWTitle(wind,defaultName);
- TitleFilter((char *)defaultName);
-
- info = (TwindowInfo *)GetWRefCon(wind);
-
- SFPutFile(where,(StringPtr)"\pSave message as:",defaultName,nil,&reply);
- if (!reply.good)
- return false;
-
- if ((err = Create(reply.fName,reply.vRefNum,kTextCreator,'TEXT')) == dupFNErr) {
- FSOpen(reply.fName,reply.vRefNum,&fRefNum);
- err = SetEOF(fRefNum,0);
- FSClose(fRefNum);
- }
- if (err != noErr)
- return false;
-
- if (FSOpen(reply.fName,reply.vRefNum,&fRefNum) != noErr)
- return false;
-
- HLock((**(TEHandle)info->data).hText);
- count = (**(TEHandle)info->data).teLength;
- FSWrite(fRefNum,&count,*(**(TEHandle)info->data).hText);
- FSClose(fRefNum);
- HUnlock((**(TEHandle)info->data).hText);
- return true;
- }
-
-
- /* DoSaveMessage is called when the user wishes to save the text
- of an article which was fetched from the network. In this case,
- the full text of the article must be fetched before the save, since
- we must allow >32k messages.
- */
-
- Boolean DoSaveMessage(TwindowInfo *info)
- {
- Point where = {100,100};
- SFReply reply;
- Str255 defaultName;
- char *text;
- long length;
- long offset,offset2,offset3;
- Handle teText;
- char messageID[256];
- OSErr err;
- short fRefNum;
- char mungeText[256];
-
- if (!FrontWindow()) {
- SysBeep(1);
- return false;
- }
-
- GetWTitle(FrontWindow(),defaultName);
-
- teText = (Handle) TEGetText((TEHandle)info->data);
-
- offset = Munger(teText,0L,"Message-ID:",11L,nil,0L);
- offset2 = Munger(teText,offset,CRSTR,1L,nil,0L);
- strcpy(mungeText,CRSTR);
- strcat(mungeText,CRSTR);
- offset3 = Munger(teText,0L,mungeText,2L,nil,0L);
-
- if (offset < 0 || offset2 < 0 || offset3 < 0 || offset2 > offset3)
- return false;
- offset += 11;
-
- HLock(teText);
- strncpy(messageID,(*teText)+offset,offset2 - offset);
- messageID[offset2-offset] = '\0';
- HUnlock(teText);
-
- if (GetArticle(nil,messageID,&text,&length,kMaxSaveLength) != noErr)
- return false;
-
- TitleFilter((char *)defaultName);
- SFPutFile(where,(StringPtr)"\pSave message as:",defaultName,nil,&reply);
- if (!reply.good)
- return false;
-
- if ((err = Create(reply.fName,reply.vRefNum,kTextCreator,'TEXT')) == dupFNErr) {
- FSOpen(reply.fName,reply.vRefNum,&fRefNum);
- err = SetEOF(fRefNum,0);
- FSClose(fRefNum);
- }
-
- if (err != noErr) {
- MyDisposPtr(text);
- return false;
- }
-
- if (FSOpen(reply.fName,reply.vRefNum,&fRefNum) != noErr) {
- MyDisposPtr(text);
- return false;
- }
-
- FSWrite(fRefNum,&length,text);
-
- FSClose(fRefNum);
- MyDisposPtr(text);
- }
-
-
- /* DoOpenFile is called when the user issues an Open Group List command
- from the File menu. This will prompt for a groups list to open.
- */
-
- void DoOpenFile(void)
- {
- Point where = {100,100};
- SFReply reply;
-
- SFGetFile(where,(StringPtr)"\p",nil,1,(OSType *)"NEWS",nil,&reply);
- if (reply.good)
- LoOpenFile(reply.fName,reply.vRefNum);
- }
-
-
- /* LoOpenFile is called by DoOpenFile once a name and vRefNum have been
- entered by the user. This routine then opens the file and parses it
- for groups.
- */
-
- OSErr LoOpenFile(Str255 fName,short vRefNum)
- {
- OSErr err;
- short fRefNum;
- long length;
- char *newsrc,*current;
- WindowPtr window;
- TwindowInfo *info;
- Point thePt;
- extern TPrefRec gPrefs;
-
- if ((err = FSOpen(fName,vRefNum,&fRefNum)) != noErr)
- return err;
- if ((err = GetEOF(fRefNum,&length)) == noErr) {
- newsrc = current = (char *)MyNewPtr(length+1);
- if ((err = MyMemErr()) == noErr) {
- if ((err = FSRead(fRefNum,&length,newsrc)) == noErr) {
- newsrc[length] = '\0';
- info = (TwindowInfo *)GetWRefCon(window = NewGroupWindow(fName));
- BlockMove(fName,info->diskFile,fName[0]+1);
- info->diskVRefNum = vRefNum;
- LDoDraw(false,(ListHandle)info->data);
- while (*current)
- ProcessLine(¤t,window);
- LDoDraw(true,(ListHandle)info->data);
- SetPt(&thePt,0,0);
- LSetSelect(true,thePt,(ListHandle)info->data);
- info->changed = false;
- info->saved = true;
- if (gPrefs.openWindowsZoomed)
- ToggleZoom(window);
- ShowWindow(window);
- SetPort(window);
- InvalRect(&window->portRect);
- }
- MyDisposPtr(newsrc);
- }
- }
- FSClose(fRefNum);
- SetCursor(&QDARROW);
- return err;
- }
-
-
- /* ProcessLine parses out a group name and group information for a single
- line in the newsrc file. The group is then added to the new window.
- */
-
- void ProcessLine(char **newsrc,WindowPtr window)
- {
- char newsGroup[256],*current;
- extern short gNumGroups;
- extern TGroup *gGroupList;
- TGroup *newGroup;
- long i,prev,totalLast,first,last;
- Boolean done;
- Cell theCell;
- short nameLen;
-
- for (current = newsGroup;
- **newsrc && **newsrc != ':' && **newsrc != '!';
- *current++ = *(*newsrc)++)
- ;
- *current = '\0';
- if (**newsrc == ':') {
- (*newsrc)++;
- for (i=0; i<gNumGroups && strcmp(newsGroup,gGroupList[i].name)!=0; i++)
- ;
- if (i<gNumGroups && (newGroup = Subscribe(&gGroupList[i],window,&theCell))) {
- prev = newGroup->read->firstRead;
- totalLast = newGroup->read->lastRead;
- MyDisposPtr((Ptr)newGroup->read);
- newGroup->read = nil;
-
- done = false;
- do {
- while (**newsrc && **newsrc != CR && **newsrc<'0' && **newsrc>'9')
- (*newsrc)++;
- if (**newsrc && **newsrc != CR) {
- GetBlank(newsrc);
- GetNumber(newsrc,&first);
- GetBlank(newsrc);
- if (**newsrc=='-') {
- (*newsrc)++;
- GetBlank(newsrc);
- GetNumber(newsrc,&last);
- }
- else
- last = first;
- if (prev <= (first-1))
- MarkRead(prev,first-1,newGroup);
- prev = last+1;
- }
- else {
- done = true;
- if (totalLast >= last+1)
- MarkRead(last+1,totalLast,newGroup);
- }
- } while (!done);
-
- if (newGroup->read==nil) {
- nameLen = 256;
- LGetCell(newsGroup,&nameLen,theCell,(ListHandle)((TwindowInfo *)GetWRefCon(window))->data);
- if ( ((unsigned char) newsGroup[nameLen-1]) != 0xff ) {
- newsGroup[strlen(newsGroup)+1] = 0xff;
- LSetCell(newsGroup,strlen(newsGroup)+2,theCell,(ListHandle)((TwindowInfo *)GetWRefCon(window))->data);
- }
- }
-
- }
- GiveTime(0);
- }
- while (**newsrc && **newsrc != CR)
- (*newsrc)++;
- if (**newsrc)
- (*newsrc)++;
- }
-
-
- /* GetNumber parses a number out of a string, returing the number and moving the
- string pointer past the position of the number.
- */
-
- void GetNumber(char **newsrc,long *number)
- {
- char *current,numStr[256];
-
- current = numStr;
- while (**newsrc && **newsrc>='0' && **newsrc<='9')
- *current++ = *(*newsrc)++;
- *current = '\0';
-
- StringToNum((StringPtr)c2pstr(numStr),number);
- }
-
-
- /* GetBlank eats blank characters from an input string.
- */
-
- void GetBlank(char **newsrc)
- {
- while (**newsrc && **newsrc == ' ' || **newsrc == ',')
- (*newsrc)++;
- }
-
-
- /* CheckForSave asks the user if he/she would like to save a group
- list before the changes have been discarded.
- */
-
- Boolean CheckForSave(WindowPtr wind)
- {
- TwindowInfo *info;
-
- info = (TwindowInfo *)GetWRefCon(wind);
- ParamText(info->diskFile,"\p","\p","\p");
- SetCursor(&QDARROW);
- switch (Alert(kCheckSaveID,CmdKeyFilter)) {
- case kYes:
- return (DoSaveFile(wind));
- break;
- case kNo:
- return true;
- break;
- case kCancel:
- return false;
- break;
- }
- }
-
-
- /* CheckForSend asks the user if he/she would like to send the message
- that they composed before the window has been closed.
- */
-
- Boolean CheckForSend(WindowPtr wind)
- {
- SetCursor(&QDARROW);
- switch (Alert(kAskSendAlert,CmdKeyFilter)) {
- case kYes:
- return (DoSendMsg((TwindowInfo *)GetWRefCon(wind)));
- break;
- case kNo:
- return true;
- case kCancel:
- return false;
- }
- }
-
-
- /* DoSaveFile is called to save a group list to disk in newsrc format.
- */
-
- Boolean DoSaveFile(WindowPtr wind)
- {
- TwindowInfo *info;
-
- info = (TwindowInfo *)GetWRefCon(wind);
- if (info->saved) {
- info->changed = false;
- return LoSaveFile(info->childList,(TGroup *)info->data2,info->diskFile,info->diskVRefNum);
- }
- else
- return DoSaveAsFile(wind);
- }
-
-
- /* DoSaveAsFile is called when the group list to be saved has not been
- written to disk before.
- */
-
- Boolean DoSaveAsFile(WindowPtr wind)
- {
- Point where = {100,100};
- SFReply reply;
- TwindowInfo *info;
- Boolean good;
-
- info = (TwindowInfo *)GetWRefCon(wind);
-
- SFPutFile(where,"\pSave group list as:",info->diskFile,nil,&reply);
- if (!reply.good)
- return false;
-
- if (good = LoSaveFile(info->childList,(TGroup *)info->data2,reply.fName,reply.vRefNum)) {
- RemoveWindowsMenu(wind);
- SetWTitle(wind,reply.fName);
- AddWindowsMenu(wind);
- BlockMove(reply.fName,info->diskFile,reply.fName[0]+1);
- info->diskVRefNum = reply.vRefNum;
- info->changed = false;
- info->saved = true;
- }
- return good;
- }
-
-
- /* LoSaveFile is the low-level routine which writes the groups out to the
- group file on disk.
- */
-
- Boolean LoSaveFile(TWList *children,TGroup *groups,Str255 fName,short vRefNum)
- {
- OSErr err;
- short fRefNum;
- long length,first;
- TGroup *theGroup;
- char tmpStr[256];
- TReadRec *read;
- TWList *current;
- short offset;
-
- /* update read lists */
-
- for (current = children; current != nil; current = current->next)
- MarkReadMsgs((TwindowInfo *) GetWRefCon(current->childWindow));
-
- if ((err = Create(fName,vRefNum,kFCreator,kFType)) == dupFNErr) {
- FSOpen(fName,vRefNum,&fRefNum);
- err = SetEOF(fRefNum,0);
- FSClose(fRefNum);
- }
- if (err != noErr)
- return false;
-
- if (FSOpen(fName,vRefNum,&fRefNum) != noErr)
- return false;
-
- for (theGroup = groups; theGroup!=nil; theGroup=theGroup->next) {
- length = strlen(theGroup->name);
- FSWrite(fRefNum,&length,theGroup->name);
- length = 2;
- FSWrite(fRefNum,&length,": ");
-
- first = 1;
- for (read = theGroup->read; read!=nil; read = read->next) {
- if ( (read->firstRead-1 - first) >= 0) {
- sprintf(tmpStr,"%lu-%lu",first,(read->firstRead-1));
- if (read->next)
- strcat(tmpStr,",");
- length = strlen(tmpStr);
- FSWrite(fRefNum,&length,tmpStr);
- }
- first = 1 + read->lastRead;
- }
-
- /* mark read to last message of group */
-
- if (theGroup->lastMess >= first) {
- sprintf(tmpStr,", %lu-%lu",first,theGroup->lastMess);
- if (first==1)
- offset=1;
- else
- offset=0;
- length = strlen(tmpStr+offset);
- FSWrite(fRefNum,&length,tmpStr+offset);
- }
-
- length = 1;
- FSWrite(fRefNum,&length,CRSTR);
- }
- FSClose(fRefNum);
- return true;
- }
-
-
- /* MarkReadMsgs is called to update the read messages list for a group.
- Each subject in the list preceeded by a √ (check mark) is marked as
- read in the internal data structure.
- */
-
- void MarkReadMsgs(TwindowInfo *theInfo)
- {
- long tmpFirst,tmpLast,i;
- TReadRec *read,*tmp;
- TGroup *theGroup;
- TSubject *subjects;
- TwindowInfo *parentInfo;
- char groupName[256];
- short nameLen;
- Cell theCell;
-
- theGroup = theInfo->parentGroup;
- parentInfo = (TwindowInfo *)GetWRefCon(theInfo->parentWindow);
- parentInfo->changed = true;
-
- subjects = (TSubject *)*(Handle)theInfo->data2;
-
- read = theGroup->read;
- while (read != nil) {
- tmp = read;
- read = read->next;
- MyDisposPtr((Ptr)tmp);
- }
- theGroup->read = nil;
-
- tmpFirst = -1;
-
- for (i=0; i<theInfo->numSubjects; i++) {
- if (!subjects[i].read && i<(theInfo->numSubjects-1) && subjects[i+1].number-subjects[i].number > 1) {
- if (tmpFirst == -1)
- tmpFirst = subjects[i].number;
- MarkRead(tmpFirst,subjects[i].number,theGroup);
- tmpFirst = -1;
- }
- else if (tmpFirst == -1 && !subjects[i].read)
- tmpFirst = tmpLast = subjects[i].number;
- else if (tmpFirst != -1 && !subjects[i].read)
- tmpLast = subjects[i].number;
- else if (tmpFirst != -1 && subjects[i].read) {
- MarkRead(tmpFirst,tmpLast,theGroup);
- tmpFirst = -1;
- }
- }
- if (tmpFirst != -1)
- MarkRead(tmpFirst,tmpLast,theGroup);
-
- if (theGroup->read==nil) {
- SetPt(&theCell,0,0);
- if (LSearch(theGroup->name,strlen(theGroup->name),CompareStart,&theCell,(ListHandle)parentInfo->data)) {
- nameLen = 256;
- LGetCell(groupName,&nameLen,theCell,(ListHandle)parentInfo->data);
- if ( ((unsigned char) groupName[nameLen-1]) != 0xff ) {
- groupName[strlen(groupName)+1] = 0xff;
- LSetCell(groupName,strlen(groupName)+2,theCell,(ListHandle)parentInfo->data);
- }
- }
- }
- }
-
-
- /* CompareStart is a string comparison routine which returns the strings as
- equal if they share a common prefix. This routine also ignores leading spaces
- and check marks.
- */
-
- pascal short CompareStart(Ptr aPtr,Ptr bPtr,short aLen,short bLen)
- {
- while (*aPtr == ' ' || *aPtr == '√') {
- aPtr++;
- aLen--;
- }
- while (*bPtr == ' ' || *bPtr == '√') {
- bPtr++;
- bLen--;
- }
-
- if (aLen < bLen)
- bLen = aLen;
- else if (bLen < aLen);
- aLen = bLen;
-
- return IUMagIDString(aPtr,bPtr,aLen,bLen);
- }
-
-
- /* MarkRead marks a range of messages _unread_ in the internal database for
- the specified group.
- */
-
- void MarkRead(long first,long last,TGroup *theGroup)
- {
- TReadRec *read,*lastRec;
-
- read = (TReadRec *)MyNewPtr(sizeof(TReadRec));
- if (MyMemErr() != noErr)
- return;
-
- read->firstRead = first;
- read->lastRead = last;
- read->next = nil;
- if (theGroup->read) {
- for (lastRec = theGroup->read; lastRec->next; lastRec=lastRec->next)
- ;
- lastRec->next = read;
- }
- else theGroup->read = read;
- }
-
-
- /* MarkXrefsRead marks articles which appear in multiple newsgroups as read
- in both of those newsgroups.
- */
-
- void MarkXrefsRead(TEHandle message,TGroup *groupList)
- {
- long offset,endHeader,endLine;
- Handle theText;
- char *current,*store;
- char xrefGroup[256];
- char xrefNumber[256];
- long number;
- char mungeText[256];
-
- strcpy(mungeText,CRSTR);
- strcat(mungeText,"Xref:");
-
- theText = (Handle) TEGetText((TEHandle)message);
- offset = Munger((Handle)theText,0L,mungeText,6L,nil,0L);
- if (offset < 0) {
- offset = Munger(theText,0L,"Xref:",5L,nil,0L);
- if (offset != 0)
- offset = -1;
- }
- if (offset < 0)
- return;
-
- strcpy(mungeText,CRSTR);
- strcat(mungeText,CRSTR);
- endHeader = Munger(theText,0L,mungeText,2L,nil,0L);
- if (offset > endHeader)
- return;
-
- endLine = Munger(theText,offset,CRSTR,1L,nil,0L);
-
- HLock(theText);
- current = (*theText)+offset;
-
- /* skip over site name */
-
- current += 6;
- while (*current == ' ' && *current != CR)
- current++;
- while (*current != ' ' && *current != CR)
- current++;
-
- /* parse xrefed groups */
-
- while (current < (*theText)+endLine) {
- store = xrefGroup;
- while (*current == ' ' && *current != CR)
- current++;
- while (*current != ':' && *current != ' ' && *current != CR) {
- *store++ = *current++;
- }
- current++;
- *store = '\0';
-
- store = xrefNumber;
- while (*current != ' ' && *current != ' ' && *current != CR)
- *store++ = *current++;
- *store = '\0';
- c2pstr(xrefNumber);
- StringToNum(xrefNumber,&number);
- MarkOneRead(xrefGroup,number,groupList);
- }
-
- HUnlock(theText);
- }
-
-
- /* MarkOneRead marks a single message in a specified group as being read.
- */
-
- void MarkOneRead(char *groupName,long number,TGroup *groupList)
- {
- TGroup *theGroup;
- TReadRec *read,*newRead,*prevRead;
-
- for (theGroup = groupList;
- theGroup && strcmp(theGroup->name,groupName)!=0;
- theGroup = theGroup->next);
-
- if (!theGroup)
- return;
-
- for (read = prevRead = theGroup->read;
- read && !(number>=read->firstRead && number<=read->lastRead);
- prevRead = read,read = read->next);
-
- if (!read) /* already read */
- return;
-
- if (number == read->firstRead) {
- read->firstRead++;
- if (read->firstRead == read->lastRead) {
- if (read != prevRead)
- prevRead->next = read->next;
- else
- theGroup->read = read->next;
- DisposPtr((Ptr)read);
- }
- return;
- }
-
- if (number == read->lastRead) {
- read->lastRead--;
- if (read->firstRead == read->lastRead) {
- if (read != prevRead)
- prevRead->next = read->next;
- else
- theGroup->read = read->next;
- DisposPtr((Ptr)read);
- }
- return;
- }
-
- /* split this one in half */
-
- newRead = (TReadRec *)NewPtr(sizeof(TReadRec));
- newRead->next = read->next;
- read->next = newRead;
- newRead->lastRead = read->lastRead;
- newRead->firstRead = number + 1;
- read->lastRead = number - 1;
- }
-
-
- /* Subscribe adds the given group to the list of groups to which the
- user is subscribed. This is called when a user drags a group from
- the main group list into his/her user group list.
- */
-
- TGroup *Subscribe(TGroup *theGroup,WindowPtr theWindow,Cell *retCell)
- {
- ListHandle theList;
- Cell theCell;
- TwindowInfo *theInfo;
- TGroup *tmpPtr,*last;
- short cellSize;
- char tmpName[256];
-
- theInfo = (TwindowInfo *)GetWRefCon(theWindow);
- theInfo->changed = true;
-
- for (tmpPtr = (TGroup *)theInfo->data2;
- tmpPtr && strcmp(theGroup->name,tmpPtr->name)!=0;
- tmpPtr = tmpPtr->next)
- ;
-
- if (tmpPtr) {
- SysBeep(1);
- return nil;
- }
-
- /* I do this to keep order by inserting at the end of newsgroups */
-
- tmpPtr = (TGroup *)MyNewPtr(sizeof(TGroup));
- if (MyMemErr() != noErr)
- return nil;
-
- strcpy(tmpPtr->name,theGroup->name);
- tmpPtr->firstMess = theGroup->firstMess;
- tmpPtr->lastMess = theGroup->lastMess;
- tmpPtr->status = theGroup->status;
-
- tmpPtr->read = (TReadRec *)MyNewPtr(sizeof(TReadRec));
- if (MyMemErr() != noErr)
- return nil;
-
- tmpPtr->read->firstRead = theGroup->firstMess;
- tmpPtr->read->lastRead = theGroup->lastMess;
- tmpPtr->read->next = nil;
-
- strcpy(tmpName,tmpPtr->name);
- if ( (tmpPtr->lastMess - tmpPtr->firstMess) <= 0 ) {
- cellSize = strlen(tmpName)+2;
- tmpName[strlen(tmpName)+1] = 0xff;
- }
- else
- cellSize = strlen(tmpName)+1;
-
- tmpPtr->next = nil;
-
- for (last = (TGroup *) theInfo->data2;
- last && last->next != nil;
- last = last->next)
- ;
- if (!last)
- theInfo->data2 = (unsigned long) tmpPtr;
- else
- last->next = tmpPtr;
-
- theList = (ListHandle)theInfo->data;
- SetPt(&theCell,0,LAddRow(1,theInfo->numGroups++,theList));
- LSetCell(tmpName,cellSize,theCell,theList);
- LDraw(theCell,theList);
-
- *retCell = theCell;
- return tmpPtr;
- }
-
-
- /* DoMarkArticleRead is called when a user selects Mark Read from the
- News menu. It marks all selected articles in window read.
- */
-
- void DoMarkArticleRead(Boolean read)
- {
- TwindowInfo *info;
- Cell theCell;
-
- if (!IsAppWindow(FrontWindow()))
- return;
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind != cSubject)
- return;
-
- theCell.h = theCell.v = 0;
- while (LGetSelect(true,&theCell,(ListHandle)info->data)) {
- LoMarkArticleRead(info,theCell,read);
- theCell.v++;
- }
- }
-
-
- /* LoMarkArticleRead is the low-level procedure which inserts check marks
- into the subjects which are passed in at theCell.
- */
-
- void LoMarkArticleRead(TwindowInfo *info,Cell theCell,Boolean read)
- {
- short nameLen;
- char *tmpStr,*tmpStr2;
- char numStr[256],title[256];
- long number,i;
-
- nameLen = 256;
- LGetCell(title,&nameLen,theCell,(ListHandle)info->data);
-
- for (tmpStr = numStr,tmpStr2 = title+1;
- *tmpStr2 != ' ' && *tmpStr2 != '√' && *tmpStr2 != '\0';
- *tmpStr++ = *tmpStr2++)
- ;
- *tmpStr = '\0';
- c2pstr(numStr);
- StringToNum(numStr,&number);
-
- if (info->parentGroup) {
- *title = (read) ? '√' : ' ';
- LSetCell(title,nameLen,theCell,(ListHandle)info->data);
- for (i=0; i<info->numSubjects && ((TSubject *)*((Handle)info->data2))[i].number != number; i++)
- ;
- if (i<=info->numSubjects)
- ((TSubject *)*((Handle)info->data2))[i].read = read;
- else
- SysBeep(1);
- }
- }
-
-
- /* DoMarkGroupRead marks all selected groups in a group window read.
- It is also called in response to a Mark Read command in the News
- menu.
- */
-
- void DoMarkGroupRead(Boolean read)
- {
- TwindowInfo *info;
- Cell theCell;
- short nameLen;
- TWList *children;
- Str255 wTitle;
- char name[256];
- Boolean matched;
- unsigned char readChar;
-
- readChar = (read) ? 0xff : 0x00;
-
- if (!IsAppWindow(FrontWindow()))
- return;
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind != cUserGroup)
- return;
-
-
- theCell.h = theCell.v = 0;
- while (LGetSelect(true,&theCell,(ListHandle)info->data)) {
- nameLen = 256;
- LGetCell(name,&nameLen,theCell,(ListHandle)info->data);
- for (matched=false,children=info->childList; children!=nil && !matched; children=children->next) {
- GetWTitle(children->childWindow,wTitle);
- p2cstr(wTitle);
- matched = (strcmp((char *)wTitle,name) == 0);
- }
- if (!matched) {
- if ( ((unsigned char) name[nameLen-1]) != readChar) {
- name[strlen(name)+1] = readChar;
- LSetCell(name,strlen(name)+2,theCell,(ListHandle)info->data);
- }
- LoMarkGroupRead(name,(TGroup *)info->data2,read);
- }
- else
- SysBeep(1);
-
- theCell.v++;
- }
- }
-
-
- /* LoMarkGroupRead marks all articles in the selected group read.
- */
-
- void LoMarkGroupRead(char groupName[256],TGroup *firstGroup,Boolean isRead)
- {
- TGroup *group;
- TReadRec *read;
-
- for (group = firstGroup;
- group != nil && strcmp(group->name,groupName)!=0;
- group = group->next)
- ;
-
- while (group->read) {
- read = group->read;
- group->read = group->read->next;
- MyDisposPtr((Ptr)read);
- }
-
- if (!isRead) {
- read = (TReadRec *) MyNewPtr(sizeof(TReadRec));
- read->firstRead = group->firstMess;
- read->lastRead = group->lastMess;
- read->next = group->read;
- group->read = read;
- }
- }
-
-
- /* SubscribeSelected subscribes the user to all selected newsgroups
- by calling Subscribe() above.
- */
-
- void SubscribeSelected(TwindowInfo *info,ListHandle srcList,WindowPtr destWindow)
- {
- Cell theCell,newCell;
- TGroup *theGroup;
- char groupName[256];
- short nameLen;
-
- SetPt(&theCell,0,0);
-
- while (LGetSelect(true,&theCell,srcList)) {
- nameLen = 256;
- LGetCell(groupName,&nameLen,theCell,srcList);
- if (FindGroup(info,groupName,&theGroup))
- Subscribe(theGroup,destWindow,&newCell);
- theCell.v++;
- }
- }
-
-
- /* HandleSubscribe is called when the user selects the Subscribe command
- from the News menu. It calls SubscribeSelected() above.
- */
-
- void HandleSubscribe(void)
- {
- TwindowInfo *info;
- WindowPtr destWindow;
- Boolean done;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind != cGroup && info->kind != cNewGroup)
- return;
-
- for (done=false,destWindow = (WindowPtr) ((WindowPeek)FrontWindow())->nextWindow;
- destWindow && (((TwindowInfo *)GetWRefCon(destWindow))->kind != cUserGroup);
- destWindow = (WindowPtr) ((WindowPeek)destWindow)->nextWindow)
- ;
- if (!destWindow)
- return;
-
- SubscribeSelected(info,(ListHandle)(info->data),destWindow);
- }
-
-
- /* HandleUnsubscribe unsubscribes the user from the selected newsgroups.
- It is called when the user selects unsubscribe from the News menu.
- */
-
- void HandleUnsubscribe(void)
- {
- TwindowInfo *info;
- ListHandle theList;
- Cell theCell;
- Str255 groupName,wTitle;
- short groupLen;
- TGroup *curGroup,*prevGroup;
- TWList *curChild;
- Boolean doDelete;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *)GetWRefCon(FrontWindow());
- if (info->kind != cUserGroup)
- return;
-
- info->changed = true;
-
- theList = (ListHandle) info->data;
- SetPt(&theCell,0,0);
-
- while (LGetSelect(true,&theCell,theList)) {
- groupLen = 256;
- LGetCell(groupName,&groupLen,theCell,theList);
- doDelete = true;
-
- for (curChild = info->childList; curChild!=nil && doDelete; curChild = curChild->next) {
- GetWTitle(curChild->childWindow,wTitle);
- p2cstr(wTitle);
- if (strcmp(wTitle,groupName)==0)
- doDelete = false;
- }
-
- if (doDelete) {
- LDelRow(1,theCell.v,theList);
- for (curGroup = prevGroup = (TGroup *)info->data2;
- curGroup && strcmp(groupName,curGroup->name)!=0;
- prevGroup = curGroup, curGroup = curGroup->next)
- ;
- if (curGroup) {
- if (curGroup==prevGroup)
- info->data2 = (long)curGroup->next;
- prevGroup->next = curGroup->next;
- MyDisposPtr((Ptr)curGroup);
- }
- }
- else theCell.v++;
- }
- }
-
-
- /* CheckGroups compares the list of groups to those stored in the preferences
- file. The groups which are new are then put into a new groups window.
- */
-
- void CheckGroups(void)
- {
- extern TGroup *gGroupList;
- extern short gNumGroups;
-
- OSErr err;
- short fRefNum;
- char *groupBuf;
- long groupLen = kMaxGroupLen;
- char *current,*group;
- long groupIndex;
- short cmp;
- Handle groupHandle = nil;
- long numGroups = 0;
-
- if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum)) != noErr)
- return;
-
- if ((err = SetFPos(fRefNum,fsFromStart,sizeof(TPrefRec))) == noErr) {
- groupBuf = (char *)MyNewPtr(groupLen);
- if (MyMemErr() != noErr) {
- FSClose(fRefNum);
- return;
- }
- err = FSRead(fRefNum,&groupLen,(Ptr)groupBuf);
- if (err != noErr && err != eofErr)
- groupLen = 0;
- groupBuf[groupLen] = '\0';
- current = groupBuf;
- groupIndex = 0;
- group = GetNextGroup(¤t);
- while (groupIndex < gNumGroups) {
- GiveTime(0);
- cmp = strcmp(group,gGroupList[groupIndex].name);
- if (*group=='\0') {
- AddNewGroup(&gGroupList[groupIndex],&groupHandle,&numGroups);
- groupIndex++;
- }
- else if (cmp==0) {
- group = GetNextGroup(¤t);
- groupIndex++;
- }
- else if (cmp>0) {
- AddNewGroup(&gGroupList[groupIndex],&groupHandle,&numGroups);
- groupIndex++;
- }
- else if (cmp<0)
- group = GetNextGroup(¤t);
- }
- MyDisposPtr(groupBuf);
- MakeNewGroupWindow(groupHandle,numGroups,"\pNew Groups");
- }
-
- FSClose(fRefNum);
- }
-
-
- /* GetNextGroup parses the next group out of the preferences file
- */
-
- char *GetNextGroup(char **current)
- {
- char *groupPos;
-
- while (**current == CR || **current == LF)
- (*current)++;
- groupPos = *current;
- while (**current && **current!=CR)
- (*current)++;
- if (**current)
- *(*current)++ = '\0';
- return groupPos;
- }
-
-
- /* AddNewGroup adds a new group (one which is not in the prefs file) to
- the New Groups window.
- */
-
- void AddNewGroup(TGroup *group,Handle *groupHandle,long *numGroups)
- {
- TGroup *groupList;
-
- if (*groupHandle == nil) {
- *groupHandle = MyNewHandle(sizeof(TGroup));
- if (MyMemErr() != noErr)
- return;
- HLock(*groupHandle);
- }
- else {
- HUnlock(*groupHandle);
- MySetHandleSize(*groupHandle,GetHandleSize(*groupHandle)+sizeof(TGroup));
- if (MyMemErr() != noErr)
- return;
- MoveHHi(*groupHandle);
- HLock(*groupHandle);
- }
- groupList = (TGroup *) **groupHandle;
- BlockMove((Ptr)group,(Ptr)&groupList[(*numGroups)++],sizeof(TGroup));
- }
-
-
- /* MakeNewGroupWindow creates a New Groups window to store the names of the
- new newsgroups.
- */
-
- void MakeNewGroupWindow(Handle groupHandle,long numGroups,char *windowName)
- {
- TwindowInfo *theInfo;
- WindowPtr theWind;
- GrafPtr savePort;
- Cell theCell;
- short i;
- Point firstOffset;
- char theName[256];
- short cellLen;
- Point thePt;
- extern TPrefRec gPrefs;
-
- if (numGroups==0)
- return;
-
- SetPt(&firstOffset,kOffLeft,kOffTop);
-
- CloseStatusWindow();
-
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cNewGroup,true,firstOffset,windowName));
-
- StatusWindow("Adding New Groups...",0);
-
- theInfo->numGroups = numGroups;
- theInfo->parentGroup = nil;
- theInfo->parentWindow = nil;
- theInfo->childList = nil;
- theInfo->data2 = (unsigned long) *groupHandle;
-
- LDoDraw(false,(ListHandle)theInfo->data);
- LAddRow(numGroups,0,(ListHandle)theInfo->data);
- SetPt(&theCell,0,0);
- for (i=0; i<numGroups; i++) {
-
- strcpy(theName,((TGroup *)*groupHandle)[i].name);
- if ((((TGroup *)*groupHandle)[i].lastMess - ((TGroup *)*groupHandle)[i].firstMess) <= 0) {
- cellLen = strlen(theName)+2;
- theName[cellLen-1] = 0xff;
- }
- else
- cellLen = strlen(theName)+1;
-
- LSetCell(theName,cellLen,theCell,(ListHandle)theInfo->data);
- theCell.v++;
- StatusWindow("Adding New Groups...",(short)(((float)(i+1)/(float)numGroups)*100));
- GiveTime(0);
- }
- StatusWindow("Adding New Groups...",100);
- GiveTime(0);
- CloseStatusWindow();
-
- LDoDraw(true,(ListHandle)theInfo->data);
- SetPt(&thePt,0,0);
- LSetSelect(true,thePt,(ListHandle)theInfo->data);
-
- if (gPrefs.openWindowsZoomed)
- ToggleZoom(theWind);
- ShowWindow(theWind);
-
- GetPort(&savePort);
- SetPort(theWind);
- InvalRect(&theWind->portRect);
- SetPort(savePort);
-
- }
-
-
- /* WriteGroups writes the list of newsgroups out to the preferences file
- before quitting the program.
- */
-
- void WriteGroups(void)
- {
- extern TGroup *gGroupList;
- extern short gNumGroups;
- short fRefNum;
- long i,count;
- OSErr err;
-
- StatusWindow("Writing group list...",0);
- if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum)) != noErr)
- return;
-
- err = SetFPos(fRefNum,fsFromStart,sizeof(TPrefRec));
- if (err == noErr || err == eofErr) {
- for (i=0; i<gNumGroups; i++) {
- count = strlen(gGroupList[i].name);
- FSWrite(fRefNum,&count,gGroupList[i].name);
- count = 1;
- FSWrite(fRefNum,&count,CRSTR);
- GiveTime(0);
- StatusWindow("Writing group list...",(short)(((float)(i+1)/(float)gNumGroups)*100));
- }
- StatusWindow("Writing group list...",100);
- GiveTime(0);
- }
- FSClose(fRefNum);
- }
-
-
- /* MakeFollowUp creates a new article template for a follow-up back to
- a newsgroup.
- */
-
- void MakeFollowUp(void)
- {
- DialogPtr theDlg;
- short item;
- TwindowInfo *theInfo;
- WindowPtr oldWind,theWind;
- Point firstOffset;
- GrafPtr savePort;
- char subjectStr[256],groupStr[256],fromStr[256],distStr[256],refStr[256];
- short iType;
- Handle iHndl;
- Rect iRect;
- extern TPrefRec gPrefs;
- Handle theHndl;
- long offset,offset2;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- SetCursor(&QDARROW);
-
- oldWind = FrontWindow();
-
- SetPt(&firstOffset,0,0);
- GetPort(&savePort);
- SetPort(oldWind);
- LocalToGlobal(&firstOffset);
- SetPort(savePort);
-
- if (CautionAlert(kPostAlert,nil) != okButton)
- return;
-
- SetCursor(&QDARROW);
-
- theDlg = GetNewDialog(kPostDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- theInfo = (TwindowInfo *) GetWRefCon(oldWind);
- theHndl = (Handle) TEGetText((TEHandle)theInfo->data);
- HLock(theHndl);
-
- /* copy subject field */
-
- offset = Munger(theHndl,0L,"Subject: ",9L,nil,0L);
- offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
- if (offset2 > offset && (offset2-offset) < 255 ) {
- strcpy(subjectStr,"Re: ");
- if (strncmp( (*theHndl)+offset+9,"Re: ",4) == 0)
- offset += 4;
- BlockMove( (*theHndl)+offset+9,(Ptr) (subjectStr+4),(offset2-offset-9));
- subjectStr[offset2-offset-9+4] = '\0';
- c2pstr(subjectStr);
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- SetIText(iHndl,subjectStr);
- }
-
- /* copy newsgroups field */
-
- offset = Munger(theHndl,0L,"Newsgroups: ",12L,nil,0L);
- offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
- if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
- BlockMove( (*theHndl)+offset+12,(Ptr) groupStr,(offset2-offset-12));
- groupStr[offset2-offset-12] = '\0';
- c2pstr(groupStr);
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- SetIText(iHndl,groupStr);
- }
-
- /* copy distribution field */
-
- offset = Munger(theHndl,0L,"Distribution: ",14L,nil,0L);
- offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
- if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
- BlockMove( (*theHndl)+offset+14,(Ptr) distStr,(offset2-offset-14));
- distStr[offset2-offset-14] = '\0';
- c2pstr(distStr);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- SetIText(iHndl,distStr);
- }
-
- HUnlock(theHndl);
-
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.fullName));
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.organization));
- GetDItem(theDlg,8,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.address));
-
- SelIText(theDlg,3,32767,32767);
-
- do
- ModalDialog(CmdKeyFilter,&item);
- while (item != okButton && item != cancelButton);
-
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- GetIText(iHndl,groupStr);
- p2cstr(groupStr);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- GetIText(iHndl,distStr);
- p2cstr(distStr);
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- GetIText(iHndl,subjectStr);
-
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.fullName);
- p2cstr(gPrefs.fullName);
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.organization);
- p2cstr(gPrefs.organization);
-
- GetDItem(theDlg,8,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.address);
- p2cstr(gPrefs.address);
-
- strcpy(fromStr,gPrefs.address);
- strcat(fromStr," (");
- strcat(fromStr,gPrefs.fullName);
- strcat(fromStr,")");
-
- DisposDialog(theDlg);
-
- if (item == cancelButton)
- return;
-
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cPostMessage,true,firstOffset,subjectStr));
-
- theInfo->changed = true;
- IncludeQuote(oldWind,theWind,refStr);
- AddHeader("Path: ",gPrefs.address,theWind);
- AddHeader("From: ",fromStr,theWind);
- AddHeader("Newsgroups: ",groupStr,theWind);
- AddHeader("Distribution: ",distStr,theWind);
- AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
- AddHeader("References:",refStr,theWind);
- AddHeader("Organization: ",gPrefs.organization,theWind);
- AddHeader("","",theWind);
-
- ShowWindow(theWind);
-
- GetPort(&savePort);
- SetPort(theWind);
- RedoControls(theWind);
- FixText(theWind);
- InvalRect(&theWind->portRect);
- SetPort(savePort);
- }
-
-
- /* MakeRespond creates a new message template for an e-mail response to
- a news article.
- */
-
- void MakeRespond(void)
- {
- DialogPtr theDlg;
- short item;
- TwindowInfo *theInfo;
- WindowPtr oldWind,theWind;
- Point firstOffset;
- GrafPtr savePort;
- char recipStr[256],subjectStr[256],fromStr[256],refStr[256];
- short iType;
- Handle iHndl,theHndl;
- Rect iRect;
- extern TPrefRec gPrefs;
- long offset,offset2,offset3;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- SetCursor(&QDARROW);
-
- oldWind = FrontWindow();
- SetPt(&firstOffset,0,0);
- GetPort(&savePort);
- SetPort(oldWind);
- LocalToGlobal(&firstOffset);
- SetPort(savePort);
-
- SetCursor(&QDARROW);
-
- theDlg = GetNewDialog(kRespDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- theInfo = (TwindowInfo *) GetWRefCon(oldWind);
- theHndl = (Handle) TEGetText((TEHandle)theInfo->data);
- HLock(theHndl);
-
- /* copy subject field */
-
- offset = Munger(theHndl,0L,"Subject: ",9L,nil,0L);
- offset2 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
- if (offset2 > offset && (offset2-offset) < 255 ) {
- strcpy(subjectStr,"Re: ");
- if (strncmp( (*theHndl)+offset+9,"Re: ",4) == 0)
- offset += 4;
- BlockMove( (*theHndl)+offset+9,(Ptr) (subjectStr+4),(offset2-offset-9));
- subjectStr[offset2-offset-9+4] = '\0';
- c2pstr(subjectStr);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- SetIText(iHndl,subjectStr);
- }
-
- /* copy recipient field */
-
- offset = Munger(theHndl,0L,"From: ",6L,nil,0L);
- offset2 = Munger(theHndl,offset,"(",1L,nil,0L);
- offset3 = Munger(theHndl,offset,CRSTR,1L,nil,0L);
- if (offset2 < 0 || offset3 < offset2)
- offset2 = offset3;
- if (offset > 0 && offset2 > 0 && (offset2-offset) < 255 ) {
- BlockMove( (*theHndl)+offset+6,(Ptr) recipStr,(offset2-offset-6));
- recipStr[offset2-offset-6] = '\0';
- c2pstr(recipStr);
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- SetIText(iHndl,recipStr);
- }
-
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.fullName));
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.organization));
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.address));
-
- HUnlock(theHndl);
-
- SelIText(theDlg,3,32767,32767);
-
- do
- ModalDialog(CmdKeyFilter,&item);
- while (item != okButton && item != cancelButton);
-
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- GetIText(iHndl,recipStr);
- p2cstr(recipStr);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- GetIText(iHndl,subjectStr);
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.fullName);
- p2cstr(gPrefs.fullName);
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.organization);
- p2cstr(gPrefs.organization);
-
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.address);
- p2cstr(gPrefs.address);
-
- strcpy(fromStr,gPrefs.address);
- strcat(fromStr," (");
- strcat(fromStr,gPrefs.fullName);
- strcat(fromStr,")");
-
- DisposDialog(theDlg);
-
- if (item == cancelButton)
- return;
-
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cSendMessage,true,firstOffset,subjectStr));
- theInfo->changed = true;
- IncludeQuote(oldWind,theWind,refStr);
-
- AddHeader("From: ",fromStr,theWind);
- AddHeader("To: ",recipStr,theWind);
- AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
- AddHeader("References:",refStr,theWind);
- AddHeader("Organization: ",gPrefs.organization,theWind);
- AddHeader("","",theWind);
-
- ShowWindow(theWind);
-
- GetPort(&savePort);
- SetPort(theWind);
- RedoControls(theWind);
- FixText(theWind);
- InvalRect(&theWind->portRect);
- SetPort(savePort);
- }
-
-
- /* MakePost creates a new article template for a new posting to a user-
- specified newsgroup.
- */
-
- void MakePost(void)
- {
- DialogPtr theDlg;
- short item;
- TwindowInfo *theInfo;
- WindowPtr theWind;
- Point firstOffset;
- short iType;
- Handle iHndl;
- Rect iRect;
- char subjectStr[256],groupStr[256],fromStr[256],distStr[256];
- GrafPtr savePort;
- extern TPrefRec gPrefs;
-
- SetCursor(&QDARROW);
-
- if (CautionAlert(kPostAlert,nil) != okButton)
- return;
-
- SetCursor(&QDARROW);
-
- theDlg = GetNewDialog(kPostDlg,nil,(WindowPtr)-1);
- OutlineOK(theDlg);
-
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.fullName));
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.organization));
- GetDItem(theDlg,8,&iType,&iHndl,&iRect);
- SetIText(iHndl,c2pstr(gPrefs.address));
-
- SelIText(theDlg,3,32767,32767);
-
- do
- ModalDialog(CmdKeyFilter,&item);
- while (item != okButton && item != cancelButton);
-
- GetDItem(theDlg,3,&iType,&iHndl,&iRect);
- GetIText(iHndl,groupStr);
- p2cstr(groupStr);
- GetDItem(theDlg,4,&iType,&iHndl,&iRect);
- GetIText(iHndl,distStr);
- p2cstr(distStr);
- GetDItem(theDlg,5,&iType,&iHndl,&iRect);
- GetIText(iHndl,subjectStr);
- GetDItem(theDlg,6,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.fullName);
- p2cstr(gPrefs.fullName);
- GetDItem(theDlg,7,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.organization);
- p2cstr(gPrefs.organization);
-
- GetDItem(theDlg,8,&iType,&iHndl,&iRect);
- GetIText(iHndl,gPrefs.address);
- p2cstr(gPrefs.address);
-
- strcpy(fromStr,gPrefs.address);
- strcat(fromStr," (");
- strcat(fromStr,gPrefs.fullName);
- strcat(fromStr,")");
-
- DisposDialog(theDlg);
-
- if (item == cancelButton)
- return;
-
- SetPt(&firstOffset,kOffLeft,kOffTop);
- theInfo = (TwindowInfo *) GetWRefCon(theWind = MakeNewWindow(cPostMessage,true,firstOffset,subjectStr));
- theInfo->changed = true;
-
- AddHeader("Path: ",gPrefs.address,theWind);
- AddHeader("From: ",fromStr,theWind);
- AddHeader("Newsgroups: ",groupStr,theWind);
- AddHeader("Distribution: ",distStr,theWind);
- AddHeader("Subject: ",(char *)p2cstr(subjectStr),theWind);
- AddHeader("Organization: ",gPrefs.organization,theWind);
- AddHeader("","",theWind);
-
- ShowWindow(theWind);
-
- GetPort(&savePort);
- SetPort(theWind);
- RedoControls(theWind);
- FixText(theWind);
- InvalRect(&theWind->portRect);
- SetPort(savePort);
- }
-
-
- /* IncludeQuote indents and includes the article to which the user is responding
- in the new article template.
- */
-
- void IncludeQuote(WindowPtr parentWindow,WindowPtr newWindow,char *refStr)
- {
- Handle text,oldText;
- long teLength;
- TwindowInfo *info;
- long offset,offset2;
- char article[256],sender[256];
- char mungeStr[256];
-
- info = (TwindowInfo *) GetWRefCon(parentWindow);
- oldText = text = (Handle) TEGetText((TEHandle)info->data);
- teLength = (**((TEHandle)info->data)).teLength;
-
- info = (TwindowInfo *) GetWRefCon(newWindow);
-
- strcpy(mungeStr,CRSTR);
- strcat(mungeStr,"Message-ID:");
- offset = Munger(oldText,0,mungeStr,12L,nil,0L);
- if (offset >= 0) {
- offset += 12;
- offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
- if (offset2 < 0)
- offset2 = offset;
- strncpy( article,(char *)*oldText+offset,offset2-offset);
- *(article+offset2-offset) = '\0';
- }
- else
- strcpy(article,"");
-
- strcpy(mungeStr,CRSTR);
- strcat(mungeStr,"From:");
- offset = Munger(oldText,0,mungeStr,6L,nil,0L);
- if (offset >= 0) {
- offset += 6;
- offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
- if (offset2 < 0)
- offset2 = offset;
- strncpy( sender,(char *)*oldText+offset,offset2-offset);
- *(sender+offset2-offset) = '\0';
- }
- else
- strcpy(sender,"...");
-
- strcpy(mungeStr,CRSTR);
- strcat(mungeStr,"References:");
- offset = Munger(oldText,0,mungeStr,12L,nil,0L);
- if (offset >= 0) {
- offset += 12;
- offset2 = Munger(oldText,offset,CRSTR,1L,nil,0L);
- if (offset2 < 0)
- offset2 = offset;
- strncpy( refStr,(char *)*oldText+offset,offset2-offset);
- *(refStr+offset2-offset) = '\0';
- }
- else
- strcpy(refStr,"");
- strcat(refStr,article);
-
- if (MyHandToHand(&text) != noErr)
- return;
- MySetHandleSize(text,teLength);
- if (MyMemErr() != noErr)
- return;
-
- strcpy(mungeStr,CRSTR);
- strcat(mungeStr,CRSTR);
- offset = Munger(text,0,mungeStr,2L,nil,0L);
- offset = Munger(text,0,nil,offset,"*",0L);
- strcpy(mungeStr,CRSTR);
- strcat(mungeStr,"> ");
- while ( (offset = Munger(text,offset,CRSTR,1L,mungeStr,3L)) >= 0)
- ;
- offset = Munger(text,0,nil,0L,"In article",10L);
- offset = Munger(text,offset,nil,0L,article,strlen(article));
- offset = Munger(text,offset,nil,0L,",",1L);
- offset = Munger(text,offset,nil,0L,sender,strlen(sender));
- offset = Munger(text,offset,nil,0L," writes:",8L);
-
- teLength = GetHandleSize(text);
- HLock(text);
- TESetText(*text,teLength,(TEHandle)info->data);
- TESetSelect(0L,0L,(TEHandle)info->data);
- HUnlock(text);
- MyDisposHandle(text);
- }
-
-
- /* AddHeader adds a header of name hName and contents hContents to the
- TextEdit field in window newWindow.
- */
-
- void AddHeader(char *hName,char *hContents,WindowPtr newWindow)
- {
- TEHandle theTE;
-
- theTE = (TEHandle) ((TwindowInfo *)GetWRefCon(newWindow))->data;
-
- TEInsert(hName,strlen(hName),theTE);
- TEInsert(hContents,strlen(hContents),theTE);
- TEInsert(CRSTR,1,theTE);
- }
-
-
- /* If user authentication were important, this routine would check to make
- sure that the "From:" header was not changed before allowing the article
- to be posted.
- */
-
- Boolean CheckHeader(TwindowInfo *info)
- {
- #pragma unused (info)
-
- /* no user authentication, so don't have to check header */
-
- return true;
- }
-